#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <linux/input.h>
#include <termios.h>
#include <errno.h>
#include "stdio.h"

#include "lvgl/lvgl.h"
#include "lvgl/demos/lv_demos.h"
#include "lv_drivers/display/fbdev.h"
#include "lv_drivers/indev/evdev.h"
#include <unistd.h>
#include <pthread.h>
#include <time.h>
#include <sys/time.h>
#include "./rfid/rfid.h"
#include <pthread.h>


int flag = 0;

extern lv_obj_t * label4;

unsigned char DataBfr[16];
unsigned char cardid[4];
unsigned char KEYA_BUF[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
unsigned char DataReadBuf[16];
unsigned char DataWriteBuf[16];
unsigned int ID;
/*计算校验和*/
unsigned char CalBCC(unsigned char *buf, int n)
{
    int i;
    unsigned char bcc=0;
    for(i = 0; i < n; i++)
    {
        bcc ^= *(buf+i);
    }
    return (~bcc);
}
int PiccRequest(int fd)
{
    unsigned char WBuf[128], RBuf[128];
    int  ret, i;
    fd_set rdfd;
    static struct timeval timeout;

    memset(WBuf, 0, 128);
    memset(RBuf,0,128);
    WBuf[0] = 0x07; //帧长= 7 Byte
    WBuf[1] = 0x82; //包号= 0 , 命令类型= 0x02
    WBuf[2] = 'A';  //命令= 'A'
    WBuf[3] = 0x01; //信息长度= 1
    WBuf[4] = 0x52; //请求模式:  ALL=0x52
    WBuf[5] = CalBCC(WBuf, WBuf[0]-2);      //校验和
    WBuf[6] = 0x03;     //结束标志

        timeout.tv_sec = 300;
        timeout.tv_usec = 0;
    FD_ZERO(&rdfd);
    FD_SET(fd,&rdfd);

    write(fd, WBuf, 7);
    ret = select(fd + 1,&rdfd, NULL,NULL,&timeout);
    //printf("3 PiccRequest......................\n");
    switch(ret)
    {
        case -1:
            perror("PiccRequest select error\n");
            break;
        case  0:
            printf("PiccRequest timed out.\n");
            break;
        default:
            ret = read(fd, RBuf, 8);
            if (ret < 0)
            {
                printf("PiccRequest ret = %d, %m\n", ret, errno);
                break;
            }
            if (RBuf[2] == 0x00)        //应答帧状态部分为0 则请求成功  返回卡的类型
            {
                    DataBfr[0] = RBuf[4];
                    DataBfr[1] = RBuf[5];
                    FD_CLR(fd,&rdfd);
                    //printf("PiccRequest success\n");
                return 0;
            }
            break;
    }
    FD_CLR(fd,&rdfd);
    return 1;
}
/*防碰撞，获取范围内最大ID*/
int PiccAnticoll(int fd)
{
    unsigned char WBuf[128], RBuf[128];
    int ret, i;
    fd_set rdfd;
    struct timeval timeout;
    

#if 0
    memset(WBuf, 0, 128);
    memset(RBuf,0,128);
    WBuf[0] = 0x0C; //帧长= 8 Byte
    WBuf[1] = 0xC2; //包号= 0 , 命令类型= 0x02
    WBuf[2] = 'B';  //命令= 'B'
    WBuf[3] = 0x06; //信息长度= 2
    WBuf[4] = 0x93; //防碰撞0x93 --一级防碰撞
    WBuf[5] = 0x0A; //位计数0
    WBuf[6] = 0xE2;
    WBuf[7] = 0xB5;
    WBuf[8] = 0x5D;
    WBuf[9] = 0xBB;
    WBuf[10] = CalBCC(WBuf, WBuf[0]-2);     //校验和
    WBuf[11] = 0x03;    //结束标志
#endif

#if 1
    memset(WBuf, 0, 128);
    memset(RBuf,0,128);
    WBuf[0] = 0x08; //帧长= 8 Byte
    WBuf[1] = 0x02; //包号= 0 , 命令类型= 0x02
    WBuf[2] = 'B';  //命令= 'B'
    WBuf[3] = 0x02; //信息长度= 2
    WBuf[4] = 0x93; //防碰撞0x93 --一级防碰撞
    WBuf[5] = 0x00; //位计数0
    WBuf[6] = CalBCC(WBuf, WBuf[0]-2);      //校验和
    WBuf[7] = 0x03;     //结束标志
#endif 

    timeout.tv_sec = 300;
    timeout.tv_usec = 0;
    FD_ZERO(&rdfd);
    FD_SET(fd,&rdfd);
    write(fd, WBuf, 8);

    ret = select(fd + 1,&rdfd, NULL,NULL,&timeout);
    switch(ret)
    {
        case -1:
            perror("PiccAnticoll select error\n");
            break;
        case  0:
            perror("PiccAnticoll Timeout:");
            break;
        default:
            ret = read(fd, RBuf, 10);
            if (ret < 0)
            {
                printf("PiccAnticoll ret = %d, %m\n", ret, errno);
                break;
            }
            if (RBuf[2] == 0x00) //应答帧状态部分为0 则获取ID 成功
            {
                ID = (RBuf[7]<<24) | (RBuf[6]<<16) | (RBuf[5]<<8) | RBuf[4];
                
                memcpy(cardid,&RBuf[4],4);
                //printf("PiccAnticoll The card ID is %x\n",ID);
                return 0;
            }
    }
    return -1;
}


int PiccSelect(int fd)
{
    unsigned char WBuf[128], RBuf[128];
    int  ret, i;
    fd_set rdfd;
    static struct timeval timeout;

    memset(WBuf, 0, 128);
    memset(RBuf,0,128);
    WBuf[0] = 0x0B; //帧长= 7 Byte
    WBuf[1] = 0x02; //包号= 0 , 命令类型= 0x02
    WBuf[2] = 'C';  //命令= 'C
    WBuf[3] = 0x05; //信息长度= 5
    WBuf[4] = 0x93; //请求模式:  ALL=0x52
        memcpy(&WBuf[5],cardid,4);
    WBuf[9] = CalBCC(WBuf, WBuf[0]-2);      //校验和
    WBuf[10] = 0x03;    //结束标志

        timeout.tv_sec = 300;
        timeout.tv_usec = 0;
    FD_ZERO(&rdfd);
    FD_SET(fd,&rdfd);
    
    write(fd, WBuf, WBuf[0]);
    ret = select(fd + 1,&rdfd, NULL,NULL,&timeout);
    switch(ret)
    {
        case -1:
            perror("PiccSelect error\n");
            break;
        case  0:
            printf("PiccSelect timed out.\n");
            break;
        default:
            ret = read(fd, RBuf, 7);
            if (ret < 0)
            {
                printf("PiccSelect  ret = %d, %m\n", ret, errno);
                break;
            }
            if (RBuf[2] == 0x00)        //应答帧状态部分为0 则请求成功
            {

                    printf("PiccSelect success, 卡类型 = %d\n", RBuf[4]);
                return 0;
            }
            break;
    }
    return -1;
}

int PiccAuthKey(int fd,int sector,unsigned char KeyAB)
{
    unsigned char WBuf[128], RBuf[128];
    int  ret, i;
    fd_set rdfd;
    static struct timeval timeout;

    memset(WBuf, 0, 128);
    memset(RBuf,0,128);
    WBuf[0] = 0x12; //帧长= 17 Byte
    WBuf[1] = 0x02; //包号= 0 , 命令类型= 0x02
    WBuf[2] = 'F';  //命令= 'F'
    WBuf[3] = 0x0C;   //信息长度= 0x0c
    WBuf[4] = KeyAB;
        memcpy(&WBuf[5],cardid,4);
        memcpy(&WBuf[9],KEYA_BUF,6);
        WBuf[15]=sector;   //读写哪个区
    WBuf[16] = CalBCC(WBuf, WBuf[0]-2);     //校验和
    WBuf[17] = 0x03;    //结束标志

        timeout.tv_sec = 300;
        timeout.tv_usec = 0;
    FD_ZERO(&rdfd);
    FD_SET(fd,&rdfd);

    write(fd, WBuf, WBuf[0]);
    ret = select(fd + 1,&rdfd, NULL,NULL,&timeout);
    switch(ret)
    {
        case -1:
            perror("PiccAuthKey error\n");
            break;
        case  0:
            printf("PiccAuthKey timed out.\n");
            break;
        default:
            ret = read(fd, RBuf, 7);
            if (ret < 0)
            {
                printf("PiccAuthKey  ret = %d, %m\n", ret, errno);
                break;
            }
            if (RBuf[2] == 0x00)        //应答帧状态部分为0 则请求成功
            {
                    printf("PiccAuthKey success\n");
                return 0;
            }
            break;
    }
    return -1;
}

int PiccRead(int fd,unsigned char sector)
{
    unsigned char WBuf[128], RBuf[128];
    int  ret, i;
    fd_set rdfd;
    static struct timeval timeout;

    memset(WBuf, 0, 128);
    memset(RBuf,0,128);
    WBuf[0] = 0x07; //帧长= 7 Byte
    WBuf[1] = 0x02; //包号= 0 , 命令类型= 0x02
    WBuf[2] = 'G';  //命令= 'g
    WBuf[3] = 0x01; //信息长度= 1
    WBuf[4] = sector;   //读哪个扇区
    WBuf[5] = CalBCC(WBuf, WBuf[0]-2);      //校验和
    WBuf[6] = 0x03;     //结束标志

        timeout.tv_sec = 300;
        timeout.tv_usec = 0;
    FD_ZERO(&rdfd);
    FD_SET(fd,&rdfd);

    write(fd, WBuf, WBuf[0]);
    ret = select(fd + 1,&rdfd, NULL,NULL,&timeout);
    switch(ret)
    {
        case -1:
            perror("PiccRead error\n");
            break;
        case  0:
            printf("PiccRead timed out.\n");
            break;
        default:
            ret = read(fd, RBuf, 23);
            if (ret < 0)
            {
                printf("PiccRead  ret = %d, %m\n", ret, errno);
                break;
            }
            if (RBuf[2] == 0x00)        //应答帧状态部分为0 则请求成功
            {
                    usleep(10*1000);
                    read(fd,&RBuf[ret],6);
                    memcpy(DataReadBuf,&RBuf[4],16); //读取到该扇区的数据

                     //printf("块数据： ");
                    //for(i=4;i<21;i++)
                        //printf(" %x",RBuf[i]);
                    //printf("\n");
                return 0;
            }
            break;
    }
    return -1;
}

int PiccWrite(int fd,unsigned char sector)
{
    unsigned char WBuf[128], RBuf[128];
    int  ret, i;
    fd_set rdfd;
    static struct timeval timeout;

    memset(WBuf, 0, 128);
    memset(RBuf,0,128);
    WBuf[0] = 23;   //帧长= 23 Byte
    WBuf[1] = 0x02; //包号= 0 , 命令类型= 0x02
    WBuf[2] = 'H';  //命令= 'H
    WBuf[3] = 0X11; //信息长度= 17
    WBuf[4] = sector;   //写哪个扇区
        memcpy(&WBuf[5],DataWriteBuf,16);
    WBuf[21] = CalBCC(WBuf, WBuf[0]-2);     //校验和
    WBuf[22] = 0x03;    //结束标志

        timeout.tv_sec = 300;
        timeout.tv_usec = 0;
    FD_ZERO(&rdfd);
    FD_SET(fd,&rdfd);
        
    write(fd, WBuf, 23);

    //printf("11111111\n");
    ret = select(fd + 1,&rdfd, NULL,NULL,&timeout);
    switch(ret)
    {
        case -1:
            perror("PiccWrite error\n");
            break;
        case  0:
            printf("PiccWrite timed out.\n");
            break;
        default:
        //printf("22222222\n");
            ret = read(fd, RBuf, 7);
            //printf("3333333333\n");
            if (ret < 0)
            {
                printf("PiccWrite  ret = %d, %m\n", ret, errno);
                break;
            }
            if (RBuf[2] == 0x00)        //应答帧状态部分为0 则请求成功
            {
                    printf("PiccWrite card success\n");
                return 0;
            }
            break;
    }
    return -1;
}



void * rfid_system (void * arg)
{
    sleep(2);
	int usart1_fd = open("/dev/ttySAC1", O_RDWR | O_NOCTTY); //该文件对应 串口COM2， O_NOCTTY，man: 如果该文件涉及到终端设备（串口），这个设备将不会成为进程的控制终端。
	if(usart1_fd == -1)
	{
		printf("open fail\n");
	}

	struct termios usart1 = {0};
	//配置波特率9600
	cfsetospeed(&usart1,B9600);//输出波特率 = 9600
	cfsetispeed(&usart1,B9600);//输入波特率 = 9600

    //配置数据位
    usart1.c_cflag &= ~CSIZE; //将原本位置填写的字符长度标识数据清空
	usart1.c_cflag |= CS8; //开启（配置）8位数据位	
    
    //配置校验位
    usart1.c_cflag &= ~PARENB;//关闭奇偶校验

    //配置停止位
    usart1.c_cflag &= ~CSTOPB;//关闭该宏表示一位停止位，打开表示两位停止位。

    //配置流控
    usart1.c_cflag &= ~CRTSCTS;//关闭流控

    //将串口配置成原始模式，解决read 函数阻塞问题
    cfmakeraw(&usart1);


    //使配置的串口生效
    tcsetattr(usart1_fd, TCSANOW,&usart1);//使你配置的串口数据，立马作用到该串口上。
    
    //保存ID的数组
    unsigned int id[255] = {0};
    int id_num = 0;
    printf("start\n");

    while(1)
    {
       // printf("*****************************************************************\n");
        PiccRequest(usart1_fd);
        PiccAnticoll(usart1_fd);
        if(ID == 0)
        {
            continue;
        }
        printf("flag = %d\n", flag);
        if(flag == 0)
        {
            printf("ID = %x\n", ID);
            for(int i = 0; i < 255; i++)
            {
                if(ID == id[i])
                {
                    printf("消费2元\n");
                    //卡选择
                    PiccSelect(usart1_fd);
                    //卡验证
                    PiccAuthKey(usart1_fd, 1, 0x60);
                    //卡读取
                    PiccRead(usart1_fd,1);
                    //printf("原始：%d\n", DataReadBuf[0]);
                    //将读到的数据-2
                    DataReadBuf[0] = DataReadBuf[0] - 2;
                    printf("余额：%d\n", DataReadBuf[0]);
                    char temp[30];
                    sprintf(temp, "surplus : %d", DataReadBuf[0]);
                    lv_label_set_text(label4, temp);
                    DataWriteBuf[0] = DataReadBuf[0];//写入的数要比16大，占有两位16进制。
                    PiccWrite(usart1_fd,1);
                    ID = 0;
                    break;
                }
            }
            sleep(1);
        }
        else
        {
            switch(flag)
            {
                case 1:
                {
                    //删除
                    for(int i = 0; i < 255; i++)
                    {
                        if(ID == id[i])
                        {
                            id[i] = 0;
                            printf("删除成功\n");
                            lv_label_set_text(label4, "cancel succes");
                            break;
                        }
                    }
                    flag = 0;
                    break;

                }
                case 2:
                {
                    //注册
                    if(ID != 0)
                    {
                        for(int i = 0; i < 255; i++)
                        {
                            if(ID == id[i])
                            {
                                printf("已经注册\n");
                              
                                lv_label_set_text(label4, "have already registered");
                                break;
                            }
                        }
                        id[id_num] = ID;
                        ID = 0;
                        printf("注册注册注册注册注册注册注册\n");
                        id_num ++;
                        flag = 0;
                    }
                    printf("已经注册的：\n");
                    for(int i = 0; i < id_num; i++)
                    {
                        printf("%d ", id[i]);
                    }
                    printf("\n");
                    break;
                }
                case 3:
                {
                    //充值
                    //卡选择
                    PiccSelect(usart1_fd);
                    //卡验证
                    PiccAuthKey(usart1_fd, 1, 0x60);
                    //卡读取
                    PiccRead(usart1_fd,1);
                    //printf("原始：%d\n", DataReadBuf[0]);
                    //将读到的数据+100
                    DataReadBuf[0] = DataReadBuf[0] + 100;
                    
                    // for(int i = 0; i < 16; i++)
                    // {
                    //     DataWriteBuf[i] = DataReadBuf[i];//写入的数要比16大，占有两位16进制。
                    // }
                    DataWriteBuf[0] = DataReadBuf[0];
                    PiccWrite(usart1_fd,1);
                    PiccRead(usart1_fd,1);
                    printf("充值后余额：%d\n", DataReadBuf[0]);
                    char temp[30];
                    sprintf(temp, "surplus : %d", DataReadBuf[0]);
                    lv_label_set_text(label4, temp);
                    ID = 0;
                    flag = 0;
                    sleep(2);
                    break;
                }
            }
        }
        
        
    }
	return NULL;
}